package com.atwisdom.star.service.business;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.atwisdom.star.common.util.JsonUtil;
import com.atwisdom.star.common.util.SpringContextUtil;
import com.atwisdom.star.common.util.UuidTool;
import com.atwisdom.star.core.dao.pojo.modelClass.hier.HierInstance;
import com.atwisdom.star.core.dao.pojo.modelClass.routing.RoutingInstance;
import com.atwisdom.star.core.dsl.modelClass.routing.Impl.RoutingInstanceDslServiceImpl;
import com.atwisdom.star.core.dsl.modelClass.workCenter.Impl.WorkCenterInstanceDslServiceImpl;
import com.atwisdom.star.exception.pojo.BusinessException;
import com.atwisdom.star.service.pojo.BasicStatus;
import com.atwisdom.star.service.status.RoutingPlanStatus;
import lombok.Data;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Data
public class Routing extends Business{
    private final RoutingInstanceDslServiceImpl routingService = SpringContextUtil.getBean(RoutingInstanceDslServiceImpl.class);
    private final WorkCenterInstanceDslServiceImpl workCenterService  = SpringContextUtil.getBean(WorkCenterInstanceDslServiceImpl.class);

    private RoutingInstance routing;
    private List<WorkCenter> workCenters;
    private List<WorkCenter> preWorkCenters;
    private List<WorkCenter> nextWorkCenters;
    private List<WorkCenter> currentWorkCenters;

    private final String workCenterName = "workCenter";
    private final String routingModel = "routing";
    private final String routingType = "routing";
    private final String rootNodeId = "_root";

    /**
     * 更新工艺路径状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateRoutingStatus(Long id,String status){
        RoutingPlanStatus routingPlanStatus = new RoutingPlanStatus(id);
        if(status.equals(routingPlanStatus.getStatus())){//状态不变不做更改
            return;
        }
        routingPlanStatus.setUpdateStatus(routingPlanStatus.getStatusKey(),status);
        routingPlanStatus.next();
    }

    /**
     * 回退工艺路径状态
     * @param id 实例id
     * @param status 状态
     */
    public void updateOrderStatusBack(Long id,String status){
        RoutingPlanStatus routingPlanStatus = new RoutingPlanStatus(id);
        routingPlanStatus.setUpdateStatus(routingPlanStatus.getStatusKey(),status);
        routingPlanStatus.back();
    }

    /**
     * 根据名称获取父级id
     * @param name 父级名称
     * @return
     */
    private String getParentIdByName(String name){
        List<HierInstance> hierList = routing.getHierInstances().stream().filter(hierInstance -> name.equals(hierInstance.getName())).collect(Collectors.toList());
        if(CollectionUtil.isEmpty(hierList)){
            throw new BusinessException("父级"+name+"不存在");
        }
        return hierList.get(0).getNodeId();
    }

    /**
     * 获取工作中心hier数据
     * @return List<WorkCenter>
     */
    private List<HierInstance> getWorkCenterHierList() {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> workCenterName.equals(hierInstance.getName()))
                .collect(Collectors.toList());
    }

    /**
     * 获取工作中心hier数据
     * @return List<WorkCenter>
     */
    private List<HierInstance> getWorkCenterHierList(List<String> workCenterNames) {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> workCenterName.equals(hierInstance.getName())&&workCenterNames.contains(hierInstance.getValues().getString("workCenterName")))
                .collect(Collectors.toList());
    }

    /**
     * 获取工作中心实例
     * @return List<WorkCenter>
     */
    private List<WorkCenter> getWorkCenterInstances() {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> workCenterName.equals(hierInstance.getName())&&null!=hierInstance.getLinkId())
                .map(hierInstance ->{
                    WorkCenter workCenter = new WorkCenter();
                    workCenter.setWorkCenter(workCenterService.queryById(hierInstance.getLinkId()));
                    return workCenter;
                }).collect(Collectors.toList());
    }

    /**
     * 获取nodeId数组当前工作中心实例
     * @return List<WorkCenter>
     */
    private List<WorkCenter> getCurrentWorkCenterInstances(List<String> nodeIds) {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> nodeIds.contains(hierInstance.getNodeId()) &&null!=hierInstance.getLinkId())
                .map(hierInstance ->{
                    WorkCenter workCenter = new WorkCenter();
                    workCenter.setWorkCenter(workCenterService.queryById(hierInstance.getLinkId()));
                    return workCenter;
                }).collect(Collectors.toList());
    }

    /**
     * 获取nodeId数组下一工作中心实例
     * @return List<WorkCenter>
     */
    private List<WorkCenter> getNextWorkCenterInstances(List<String> nodeIds) {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> CollectionUtil.intersection(new JSONArray(nodeIds),hierInstance.getPrev()).size()>0 &&null!=hierInstance.getLinkId())
                .map(hierInstance ->{
                    WorkCenter workCenter = new WorkCenter();
                    workCenter.setWorkCenter(workCenterService.queryById(hierInstance.getLinkId()));
                    return workCenter;
                }).collect(Collectors.toList());
    }

    /**
     * 获取nodeId数组当前LinkId
     * @return List<Long>
     */
    private List<Long> getLinkIdListByNodeIds(List<String> nodeIds) {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> nodeIds.contains(hierInstance.getNodeId()) &&null!=hierInstance.getLinkId())
                .map(hierInstance ->hierInstance.getLinkId()).collect(Collectors.toList());
    }

    /**
     * 根据nodeId数组，获取数组下的下一节点数组
     * @param nodeIds nodeId 数组
     * @return 下一节点数组
     */
    private List<String> getNextWorkCenterNodeIds(List<String> nodeIds) {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> CollectionUtil.intersection(new JSONArray(nodeIds),hierInstance.getPrev()).size()>0 &&null!=hierInstance.getLinkId())
                .map(hierInstance ->hierInstance.getNodeId()).collect(Collectors.toList());
    }

    /**
     * 根据工作中心id数组，获取当前节点nodeId数组
     * @param linkIds 工作中心Id数组
     * @return 当前节点数组
     */
    private List<String> getCurrentWorkCenterNodeIds(List<Long> linkIds) {
        return routing.getHierInstances().stream()
                .filter(hierInstance -> linkIds.contains(hierInstance.getLinkId()))
                .map(hierInstance ->hierInstance.getNodeId()).collect(Collectors.toList());
    }

    /**
     * 根据工作中心id数组，获取上一节点nodeId数组
     * @param linkIds 工作中心Id数组
     * @return 上一节点数组
     */
    private List<String> getPreWorkCenterNodeIds(List<Long> linkIds) {
        List<String> nodeIds = new ArrayList<>();
        routing.getHierInstances().stream()
        .filter(hierInstance -> linkIds.contains(hierInstance.getLinkId()))
        .forEach(hierInstance ->nodeIds.addAll(hierInstance.getPrev().toJavaList(String.class)));
        return nodeIds;
    }

    /**
     * 根据id初始化工艺路径
     * @param id 工艺路径id
     */

    public void setRouting(Long id) {
        setRouting(routingService.queryInsWithHierById(id));
    }

    /**
     * 根据工艺路径实例初始化工艺路径
     * @param routing 工艺路径实例
     */
    public void setRouting(RoutingInstance routing){
        if(null==routing){
            throw new BusinessException("工艺路径不存在");
        }
        this.routing = routing;
        this.workCenters = getWorkCenterInstances();
        initCurrentWorkCenters();
    }

    /*
     * 初始化当前工作中心
     */
    public void initCurrentWorkCenters(){
        JSONObject routingJson = routingUtil.getRoutingInsJsonObjectList(this.routing);
        JSONArray workCenterIds = JSONArray.parseArray(JsonUtil.get(routingJson,"values.currentWorkCenter"));
        if(CollectionUtils.isEmpty(workCenterIds)){
            this.preWorkCenters = new ArrayList<>();
            this.currentWorkCenters = new ArrayList<>();
            this.nextWorkCenters = getNextWorkCenterInstances(Arrays.asList(rootNodeId));
        }else{
            this.currentWorkCenters = workCenterIds.stream().map(workCenterId ->{
                WorkCenter workCenter = new WorkCenter();
                workCenter.setWorkCenter(workCenterService.queryById(Long.valueOf(workCenterId.toString())));
                return workCenter;
            }).collect(Collectors.toList());
            setCurrentWorkCenters(this.currentWorkCenters);
        }
    }

    /**
     * 回退Routin状态为创建状态
     */
    public void backRouting() {
        updateOrderStatusBack(this.routing.getId(),BasicStatus.ROUTING_PLAN_STATUS_CREATE);
    }

    /**
     * 设置下一工作中心
     * 只针对于工艺路线刚初始化后的设置
     */
    public void executeRouting(){
        JSONObject routingJson = routingUtil.getRoutingInsJsonObjectList(this.routing);
        if(CollectionUtil.isEmpty(this.preWorkCenters)){
            dealBeginRoutingJson(routingJson);
        }
        this.preWorkCenters = this.currentWorkCenters;
        this.currentWorkCenters = this.nextWorkCenters;
        List<Long> linkIds = this.currentWorkCenters.stream().map(workCenter -> workCenter.getWorkCenter().getId()).collect(Collectors.toList());
        this.nextWorkCenters = getNextWorkCenterInstances(getCurrentWorkCenterNodeIds(linkIds));
        routingJson.getJSONObject("values").put("currentWorkCenter",String.valueOf(linkIds));
        if(CollectionUtil.isEmpty(linkIds)){
            dealEndRoutingJson(routingJson);
        }
        updateRoutingStatus(this.routing.getId(), BasicStatus.ROUTING_PLAN_STATUS_EXECUTE);
        //更新Routing实例数据
        this.routing = routingService.queryInsWithHierById(routing.getId());
        JSONObject values = routingJson.getJSONObject("values");
        values.put("routingId",routing.getId());
        this.workCenters.forEach(workCenter -> {
            workCenter.execute(values);
        });
    }

    /**
     * 处理routing开始数据
     * @param routingJson
     */
    private void dealBeginRoutingJson(JSONObject routingJson) {
//        routingJson.getJSONObject("values").put("status","开始");
        routingJson.getJSONObject("values").put("startTime", DateUtil.now());
    }

    /**
     * 处理routing结束数据
     * @param routingJson
     */
    private void dealEndRoutingJson(JSONObject routingJson) {
//        routingJson.getJSONObject("values").put("status","结束");
        routingJson.getJSONObject("values").put("endTime", DateUtil.now());
    }

    /**
     * 完结当前工作中心，进入下一工作中心
     * @param workCenter 当前工作中心
     */
    public void finishWorkCenter(WorkCenter workCenter){
        //去掉当前工作中心，加入下一工作中心
        List<WorkCenter> currentWorkCenters = this.currentWorkCenters.stream().filter(item -> !workCenter.getWorkCenter().getId().equals(item.getWorkCenter().getId())).collect(Collectors.toList());
        currentWorkCenters.addAll(getNextWorkCenterInstances(getCurrentWorkCenterNodeIds(Arrays.asList(workCenter.getWorkCenter().getId()))));
        setCurrentWorkCenters(currentWorkCenters);
    }

    /**
     * 设置当前工作中心
     * @param currentWorkCenters
     */
    public void setCurrentWorkCenters(List<WorkCenter> currentWorkCenters) {
        JSONObject routingJson = routingUtil.getRoutingInsJsonObjectList(this.routing);
        String status = "";
        if(CollectionUtil.isEmpty(this.preWorkCenters)){
            dealBeginRoutingJson(routingJson);
        }
        this.currentWorkCenters = currentWorkCenters;
        List<Long> linkIds = this.currentWorkCenters.stream().map(workCenter -> workCenter.getWorkCenter().getId()).collect(Collectors.toList());
        routingJson.getJSONObject("values").put("currentWorkCenter",String.valueOf(linkIds));
        this.nextWorkCenters = getNextWorkCenterInstances(getCurrentWorkCenterNodeIds(linkIds));
        this.preWorkCenters = getCurrentWorkCenterInstances(getPreWorkCenterNodeIds(linkIds));
        if(CollectionUtil.isEmpty(linkIds)){
            dealEndRoutingJson(routingJson);
            status = BasicStatus.ROUTING_PLAN_STATUS_FINISH;
        }
        routingService.updateById(routingJson);
        if(StrUtil.isNotEmpty(status)){
            updateRoutingStatus(this.routing.getId(),status);
        }
        //更新Routing实例数据
        this.routing = routingService.queryInsWithHierById(routing.getId());
    }



    /**
     * 初始化工艺路径
     * @param className 工艺路径className
     * @param values 工艺路径初始数据
     */
    public void initRouting(String className, JSONObject values){
        values.put("startTime",DateUtil.now());
        this.routing  = routingUtil.add(routingType,className,UuidTool.getUUID32(),values);
        /*List<HierInstance> hiers = getWorkCenterHierList();
        this.workCenters = hiers.stream().map(hierInstance -> {
            WorkCenter workCenter = new WorkCenter();
            workCenter.initWorkCenter(hierInstance.getLinkClassName(),values);
            hierInstance.setLinkId(workCenter.getWorkCenter().getId());
            hierInstanceDslServiceImpl.updateById(hierInstance);
            return workCenter;
        }).collect(Collectors.toList());*/
        initCurrentWorkCenters();
    }

    /**
     * 初始化工艺路径工作中心
     * @param workCenterNames 工艺工作中心名称
     */
    public void initRoutingWorkCenter(List<String> workCenterNames) {
        List<HierInstance> hiers = getWorkCenterHierList(workCenterNames);
        hiers.stream().map(hierInstance -> {
            WorkCenter workCenter = new WorkCenter();
            workCenter.initWorkCenter(hierInstance.getLinkClassName(),new JSONObject());
            hierInstance.setLinkId(workCenter.getWorkCenter().getId());
            hierInstanceDslServiceImpl.updateById(hierInstance);
            return workCenter;
        }).collect(Collectors.toList());
    }

    /**
     * 取消初始化工艺路径工作中心
     * @param delWorkCenterIds 要删除的工作中心id
     */
    public void cancelRoutingWorkCenter(List<Long> delWorkCenterIds) {
        if(CollectionUtil.isEmpty(delWorkCenterIds)){
            return;
        }
        List<Long> workCenterIds = this.workCenters.stream().map(workCenter -> workCenter.getWorkCenter().getId()).collect(Collectors.toList());
        for(Long id:delWorkCenterIds){
            if(!workCenterIds.contains(id)){
                throw new BusinessException("工作中心id不存在routing中");
            }
            List<HierInstance> hierList = routing.getHierInstances().stream()
                    .filter(hierInstance -> id.equals(hierInstance.getLinkId()))
                    .map(hierInstance ->{
                        hierInstance.setLinkId(null);
                        return hierInstance;
                    }).collect(Collectors.toList());
            hierInstanceDslServiceImpl.updateNullById(hierList.get(0));
        }

        workCenterService.deleteByIdsNotDeleteLink(delWorkCenterIds);
    }

    /**
     * 删除routing
     */
    public void delete(){
        routingService.deleteByIds(Arrays.asList(routing.getId()));
        this.workCenters.forEach(workCenter -> workCenter.delete());
    }

    /**
     * 获取routingJson
     * @param id 模型id
     * @param className 类名
     * @param type 类型
     * @param values 值
     * @return
     */
    private JSONObject getRoutingJson(Long id, String className,String type,JSONObject values){
        values.putAll(JsonUtil.buildJson(new Object[]{"status","结束","endTime", DateUtil.now()}));
        return JsonUtil.buildJson(new Object[]{"id",id,"className",className,"type",type,"values",values});
    }

    /**
     * 获取Routing的json数据
     * @return Routing的json数据
     */
    public JSONObject getRoutingJson() {
        return routingUtil.getRoutingInsJsonObjectList(this.routing);
    }


    /**
     * 常见方法：1.创建实例方法
     * 2.获取当前WorkCenter，可能是数组,routing字段中标识当前WorkCenter
     * 3.通过Routing获取规格
     * 4.通过当前WorkCenter获取，上WorkCenter和下WorkCenter 可能是数组
     * 5.Routing状态的改变，明确字段表示，明确特征字段，通过变量加以定义
     *
     * Routing 包含多个WorkCenter,workCenter和WorkUnit一一对应
     * routing 基于哪个规格，成品规格
     * workCenter 也对应哪个规格
     */

}
